home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODFDev / ODF / Framewrk / FWPart / FWScrolr.cpp < prev    next >
Encoding:
Text File  |  1996-09-17  |  33.6 KB  |  1,061 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                FWScrolr.cpp
  4. //    Release Version:    $ ODF 2 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWFrameW.hpp"
  11.  
  12. #ifndef FWSCROLR_H
  13. #include "FWScrolr.h"
  14. #endif
  15.  
  16. #ifndef FWPART_H
  17. #include "FWPart.h"
  18. #endif
  19.  
  20. #ifndef FWFRAME_H
  21. #include "FWFrame.h"
  22. #endif
  23.  
  24. #ifndef FWSCLNOT_H
  25. #include "FWSclNot.h"
  26. #endif
  27.  
  28. #ifndef FWITERS_H
  29. #include "FWIters.h"
  30. #endif
  31.  
  32. #ifndef FWUTIL_H
  33. #include "FWUtil.h"
  34. #endif
  35.  
  36. #ifndef FWSCLBAR_H
  37. #include "FWSclBar.h"
  38. #endif
  39.  
  40. #ifndef FWNOTDEF_H
  41. #include "FWNotDef.h"
  42. #endif
  43.  
  44. #ifndef FWCONTXT_H
  45. #include "FWContxt.h"
  46. #endif
  47.  
  48. #ifndef FWEVEDEF_H
  49. #include "FWEveDef.h"
  50. #endif
  51.  
  52. // ----- OS Layer -----
  53.  
  54. #ifndef FWODGEOM_H
  55. #include "FWODGeom.h"
  56. #endif
  57.  
  58. #ifndef SLMIXOS_H
  59. #include "SLMixOS.h"
  60. #endif
  61.  
  62. #ifndef SLREGION_H
  63. #include "SLRegion.h"
  64. #endif
  65.  
  66. // ----- Foundation Layer -----
  67.  
  68. #ifndef FWAROPER_H
  69. #include "FWArOper.h"
  70. #endif
  71.  
  72. #ifndef FWSOMENV_H
  73. #include "FWSOMEnv.h"
  74. #endif
  75.  
  76. // ----- OpenDoc Includes -----
  77.  
  78. #ifndef SOM_ODFacet_xh
  79. #include <Facet.xh>
  80. #endif
  81.  
  82. #ifndef SOM_ODSession_xh
  83. #include <ODSessn.xh>
  84. #endif
  85.  
  86. #ifndef SOM_ODTransform_xh
  87. #include <Trnsform.xh>
  88. #endif
  89.  
  90. #ifndef SOM_ODWindow_xh
  91. #include <Window.xh>
  92. #endif
  93.  
  94. //========================================================================================
  95. // RunTime Info
  96. //========================================================================================
  97.  
  98. #ifdef FW_BUILD_MAC
  99. #pragma segment FW_FrameSegment
  100. #endif
  101.  
  102. //========================================================================================
  103. // Constant
  104. //========================================================================================
  105.  
  106. const FW_Fixed FW_kStdScrollUnit = FW_IntToFixed(16);
  107.  
  108. //========================================================================================
  109. // CLASS FW_CPrivBaseScroller
  110. //========================================================================================
  111.  
  112. FW_DEFINE_CLASS_M0(FW_CPrivBaseScroller)
  113.  
  114. // This class is archivable, but we provide the archiving implementation in a separate
  115. // translation unit in order to enable deadstripping of the archiving-related code
  116. // in parts that do not use archiving with this class.
  117.  
  118. //----------------------------------------------------------------------------------------
  119. // FW_CPrivBaseScroller::FW_CPrivBaseScroller
  120. //----------------------------------------------------------------------------------------
  121.  
  122. FW_CPrivBaseScroller::FW_CPrivBaseScroller() :
  123.     fHandlePageNavigationKeys(TRUE)
  124. {    
  125. }
  126.  
  127. //----------------------------------------------------------------------------------------
  128. // FW_CPrivBaseScroller::~FW_CPrivBaseScroller
  129. //----------------------------------------------------------------------------------------
  130.  
  131. FW_CPrivBaseScroller::~FW_CPrivBaseScroller()
  132. {    
  133. }
  134.  
  135. #ifdef FW_DEBUG
  136. //----------------------------------------------------------------------------------------
  137. //    FW_CPrivBaseScroller::PrivCheckFrame
  138. //----------------------------------------------------------------------------------------
  139.  
  140. void FW_CPrivBaseScroller::PrivCheckFrame(Environment*) const
  141. {
  142.     // Nothing to do. See FW_CScrollBarScroller::PrivCheckFrame
  143. }
  144. #endif
  145.  
  146. //========================================================================================
  147. // CLASS FW_CScroller
  148. //========================================================================================
  149.  
  150. FW_DEFINE_AUTO(FW_CScroller)
  151. FW_DEFINE_CLASS_M1(FW_CScroller, FW_CPrivBaseScroller)
  152.  
  153. // This class is archivable, but we provide the archiving implementation in a separate
  154. // translation unit in order to enable deadstripping of the archiving-related code
  155. // in parts that do not use archiving with this class.
  156.  
  157. //----------------------------------------------------------------------------------------
  158. // FW_CScroller::FW_CScroller
  159. //----------------------------------------------------------------------------------------
  160.  
  161. FW_CScroller::FW_CScroller(Environment* ev, FW_CFrame* frame) :
  162.     FW_CPrivBaseScroller(),
  163.     FW_MReceiver(),
  164.     fFrame(frame),
  165.     fAutoScrollInset(FW_IntToFixed(5)),
  166.     fLastAutoScrollTick(0),
  167.     fScrollUnit(FW_kStdScrollUnit, FW_kStdScrollUnit),
  168.     fTranslation(FW_kZeroPoint),
  169.     fMaxTranslation(FW_kZeroPoint)
  170. {
  171. FW_UNUSED(ev);
  172.     FW_ASSERT(fFrame);
  173.     
  174.     FW_END_CONSTRUCTOR
  175. }
  176.  
  177. //----------------------------------------------------------------------------------------
  178. // FW_CScroller::FW_CScroller
  179. //----------------------------------------------------------------------------------------
  180.  
  181. FW_CScroller::FW_CScroller(Environment* ev) :
  182.     FW_CPrivBaseScroller(),
  183.     FW_MReceiver(),
  184.     fFrame(0),
  185.     fAutoScrollInset(FW_IntToFixed(5)),
  186.     fLastAutoScrollTick(0),
  187.     fScrollUnit(FW_kStdScrollUnit, FW_kStdScrollUnit),
  188.     fTranslation(FW_kZeroPoint),
  189.     fMaxTranslation(FW_kZeroPoint)
  190. {
  191. FW_UNUSED(ev);
  192.  
  193.     FW_END_CONSTRUCTOR
  194. }
  195.  
  196. //----------------------------------------------------------------------------------------
  197. // FW_CScroller::~FW_CScroller
  198. //----------------------------------------------------------------------------------------
  199.  
  200. FW_CScroller::~FW_CScroller()
  201. {
  202.     FW_START_DESTRUCTOR
  203. }
  204.  
  205. //----------------------------------------------------------------------------------------
  206. // FW_CScroller::RegisterScrollBar
  207. //----------------------------------------------------------------------------------------
  208.  
  209. void FW_CScroller::RegisterScrollNotifier(Environment* ev, FW_MNotifier* notifier)
  210. {
  211. FW_UNUSED(ev);
  212.     // create the interest for the scroll notification
  213.     AddInterest(FW_CInterest(notifier, FW_kScrollMsg));
  214. }
  215.  
  216. //----------------------------------------------------------------------------------------
  217. // FW_CScroller::UnregisterScrollNotifier
  218. //----------------------------------------------------------------------------------------
  219.  
  220. void FW_CScroller::UnregisterScrollNotifier(Environment* ev, FW_MNotifier* notifier)
  221. {
  222. FW_UNUSED(ev);
  223.     FW_CInterest interest(notifier, FW_kScrollMsg);
  224.     RemoveInterest(interest);
  225. }
  226.  
  227. //----------------------------------------------------------------------------------------
  228. // FW_CScroller::TranslationToPixels
  229. //----------------------------------------------------------------------------------------
  230. //    By default we use pixels. Override TranslationToPixels if your scroller units are for example
  231. //    cells
  232. FW_CPoint FW_CScroller::TranslationToPixels(Environment* ev, const FW_CPoint& translation) const
  233. {
  234. FW_UNUSED(ev);
  235.  
  236.     return translation;
  237. }
  238.  
  239. //----------------------------------------------------------------------------------------
  240. // FW_CScroller::HandleNotification
  241. //----------------------------------------------------------------------------------------
  242.  
  243. void FW_CScroller::HandleNotification(Environment* ev, const FW_CNotification& notification)
  244. {
  245.     if (notification.GetMessage() == FW_kScrollMsg)
  246.     {
  247.         const FW_CScrollNotification& scrollNfy = (FW_CScrollNotification&) notification;
  248.     
  249.         FW_CPoint oldPos = fTranslation;
  250.         
  251.         FW_XYSelector direction = scrollNfy.GetDirection(ev);
  252.         fTranslation[direction] += scrollNfy.GetDelta(ev);
  253.         
  254.         PrivChangeFrameInternalTransform(ev, oldPos, fTranslation, direction, scrollNfy.ShouldScroll(ev));
  255.     }
  256. }
  257.  
  258. //----------------------------------------------------------------------------------------
  259. // FW_CScroller::PrivScrollDraw
  260. //----------------------------------------------------------------------------------------
  261. // by is in pixels
  262.  
  263. void FW_CScroller::PrivScrollDraw(Environment* ev, FW_Fixed by, FW_XYSelector direction)
  264. {    
  265.     FW_CAcquiredODTransform aqFrameInternal = fFrame->AcquireInternalTransform(ev);
  266.     
  267.     FW_CPoint scale;
  268.     aqFrameInternal->GetScale(ev, (ODPoint*)&scale);
  269.     
  270.     FW_Wide wideBy[2];
  271.     wideBy[FW_kHorizontal] = wideBy[FW_kVertical] = FW_IntToWide(0);
  272.     wideBy[direction] = FW_WideMultiply(by, scale[direction]);
  273.  
  274. #ifdef FW_BUILD_MAC
  275.     FW_CAcquiredODWindow window = fFrame->AcquireODWindow(ev);
  276.     ODPlatformWindow platformWindow = window->GetPlatformWindow(ev);
  277.     
  278.     GrafPtr port;
  279.     ::GetPort(&port);
  280.     ::SetPort(platformWindow);
  281.     Point origin;
  282.     origin.h = platformWindow->portRect.left;
  283.     origin.v = platformWindow->portRect.top;
  284.     ODRgnHandle clipRgn = ::FW_NewRegion();
  285.     ::GetClip(clipRgn);
  286.     
  287.     ::SetOrigin(0, 0);    
  288. #endif
  289.  
  290.     // ------ Scroll all Facets of the frame
  291.     FW_CFrameFacetIterator ite(ev, fFrame);
  292.     for (ODFacet* facet = ite.First(ev); ite.IsNotComplete(ev); facet = ite.Next(ev))
  293.     {
  294. #ifdef FW_BUILD_MAC        
  295.         FW_CAcquiredODShape aqScrollShape = PrivCreateContentScrollShape(ev, direction);    
  296.  
  297.         // converts to window coordinates    
  298.         FW_CAcquiredODTransform aqWindowFrameTransform = facet->AcquireWindowFrameTransform(ev, NULL);
  299.         aqScrollShape->Transform(ev, aqWindowFrameTransform);
  300.         
  301.         FW_CPlatformRect platformRect = FW_GetShapeBoundingBox(ev, aqScrollShape);
  302.         
  303.         // get clip shape in window coordinates & intersect with scrollShape
  304.         FW_CAcquiredODShape aqAggregateClipShape = FW_CopyAndRelease(ev, facet->AcquireAggregateClipShape(ev, NULL));
  305.         aqAggregateClipShape->Transform(ev, aqWindowFrameTransform);
  306.         
  307.         aqAggregateClipShape->Intersect(ev, aqScrollShape);
  308.         
  309.         RgnHandle aggregateClipRgn = aqAggregateClipShape->GetQDRegion(ev);
  310.         ::SetClip(aggregateClipRgn);
  311.         
  312.         RgnHandle invalidRgn = ::FW_NewRegion();    // will be adopted by aqInvalidShape. No need to dispose it
  313.         ::ScrollRect(&platformRect, FW_WideToInt(wideBy[FW_kHorizontal]), FW_WideToInt(wideBy[FW_kVertical]), invalidRgn);
  314.         
  315.         FW_CAcquiredODShape aqInvalidShape = ::FW_NewODShape(ev, invalidRgn);
  316.         aqInvalidShape->InverseTransform(ev, aqWindowFrameTransform);
  317.  
  318.         // ----- Update the facet -----
  319.         facet->Invalidate(ev, aqInvalidShape, NULL);
  320.         facet->GetWindow(ev)->Update(ev);    
  321. #endif
  322.  
  323. #ifdef FW_BUILD_WIN
  324.         FW_DEBUG_MESSAGE("Needs to be redone");
  325. #endif
  326.     }
  327.  
  328. #ifdef FW_BUILD_MAC
  329.     ::SetPort(platformWindow);
  330.     ::SetClip(clipRgn);
  331.     ::FW_DisposeRegion(clipRgn);
  332.     ::SetOrigin(-origin.h, -origin.v);
  333.     ::SetPort(port);
  334. #endif
  335. }
  336.  
  337. //----------------------------------------------------------------------------------------
  338. //    FW_CScroller::ScaleBy
  339. //----------------------------------------------------------------------------------------
  340.  
  341. void FW_CScroller::ScaleBy(Environment* ev, const FW_CPoint& scaling, FW_CGraphicContext* gc)
  342. {
  343.     FW_ASSERT(scaling.x != FW_kFixed0 && scaling.y != FW_kFixed0);
  344.     
  345.     FW_CAcquiredODTransform aqInternal = fFrame->AcquireInternalTransform(ev);
  346.     FW_CPoint contentLocation = fFrame->PrivGetContentViewOffset(ev);
  347.     
  348.     aqInternal->MoveBy(ev, (ODPoint*)&(-contentLocation));
  349.     
  350.     FW_CPoint prevScaling;
  351.     aqInternal->GetScale(ev, (ODPoint*)&prevScaling);
  352.     aqInternal->ScaleDownBy(ev, (ODPoint*)&prevScaling);
  353.     
  354.     aqInternal->ScaleBy(ev, (ODPoint*)&scaling);
  355.     aqInternal->MoveBy(ev, (ODPoint*)&contentLocation);
  356.     
  357.     fFrame->PrivChangeInternalTransform(ev, aqInternal);
  358.     
  359.     UpdateScrollParameters(ev);
  360.     
  361.     if (gc)
  362.         gc->Reset();
  363.         
  364.     fFrame->Invalidate(ev);    // Invalidate the whole frame
  365. }
  366.  
  367. //----------------------------------------------------------------------------------------
  368. //    FW_CScroller::PrivChangeFrameInternalTransform
  369. //----------------------------------------------------------------------------------------
  370.  
  371. void FW_CScroller::PrivChangeFrameInternalTransform(Environment* ev, 
  372.                                                     const FW_CPoint& odlTranslation,
  373.                                                     const FW_CPoint& newTranslation,
  374.                                                     FW_XYSelector direction, 
  375.                                                     FW_Boolean scroll)
  376. {    
  377.     FW_CAcquiredODTransform aqFrameInternal = fFrame->AcquireInternalTransform(ev);
  378.  
  379.     FW_CPoint scale;
  380.     aqFrameInternal->GetScale(ev, (ODPoint*)&scale);
  381.  
  382.     FW_CPoint translation = -TranslationToPixels(ev, newTranslation);
  383.     
  384.     aqFrameInternal->SetOffset(ev, (ODPoint*)&translation);
  385.  
  386.     aqFrameInternal->ScaleBy(ev, (ODPoint*)&scale);
  387.  
  388.     // ----- Add the content view offset -----
  389.     FW_CPoint temp = fFrame->PrivGetContentViewOffset(ev);
  390.     aqFrameInternal->MoveBy(ev, (ODPoint*)&temp);
  391.     
  392.     fFrame->PrivChangeInternalTransform(ev, aqFrameInternal);
  393.  
  394.     if (scroll)
  395.     {
  396.         FW_CPoint offset = translation + TranslationToPixels(ev, odlTranslation);
  397.         if (offset[direction] != FW_kFixed0)
  398.             PrivScrollDraw(ev, offset[direction], direction);
  399.     }
  400.     
  401.     // ----- Notify -----
  402.     ScrollPositionChanged(ev, odlTranslation[direction], newTranslation[direction], direction);
  403. }
  404.  
  405. //----------------------------------------------------------------------------------------
  406. // FW_CScroller::CalcMaxTranslation
  407. //----------------------------------------------------------------------------------------
  408. //    By default the fMaxTranslation is equal to the extent minus the scrolling area size
  409.  
  410. FW_Fixed FW_CScroller::CalcMaxTranslation(Environment* ev, FW_Fixed scrollingArea, FW_XYSelector direction)
  411. {
  412.     FW_CPoint extent = fFrame->GetContentView(ev)->GetExtent(ev);
  413.     return extent[direction] - scrollingArea;
  414. }
  415.  
  416. //----------------------------------------------------------------------------------------
  417. // FW_CScroller::PrivAdjustTranslations
  418. //----------------------------------------------------------------------------------------
  419.  
  420. void FW_CScroller::PrivAdjustTranslations(Environment* ev, 
  421.                                         FW_XYSelector direction,
  422.                                         FW_Fixed translation, 
  423.                                         FW_Fixed scrollingArea)
  424. {
  425. FW_UNUSED(ev);
  426.  
  427.     fTranslation[direction] = translation;
  428.     
  429.     // ----- calculate the maximum
  430.     fMaxTranslation[direction] = CalcMaxTranslation(ev, scrollingArea, direction);
  431.     if (fMaxTranslation[direction] < FW_kFixed0)
  432.         fMaxTranslation[direction] = FW_kFixed0;
  433.             
  434.     // ----- Adjust the translation if necessary -----
  435.     if (fTranslation[direction] > fMaxTranslation[direction])
  436.         fTranslation[direction] = fMaxTranslation[direction];
  437.     
  438.     if (fTranslation[direction] < FW_kFixed0)
  439.         fTranslation[direction] = FW_kFixed0;
  440. }
  441.  
  442. //----------------------------------------------------------------------------------------
  443. // FW_CScroller::GetScrollingArea
  444. //----------------------------------------------------------------------------------------
  445. //    GetScrollingArea returns the area in content coordinate of the content view
  446.  
  447. FW_CRect FW_CScroller::GetScrollingArea(Environment* ev) const
  448. {
  449.     return fFrame->GetContentView(ev)->GetBoundsInContent(ev);
  450. }
  451.     
  452. //----------------------------------------------------------------------------------------
  453. // FW_CScroller::UpdateScrollParameters
  454. //----------------------------------------------------------------------------------------
  455.  
  456. void FW_CScroller::UpdateScrollParameters(Environment* ev)
  457. {
  458.     FW_CRect boundsInContent = GetScrollingArea(ev);
  459.     
  460.     FW_CPoint oldPos(fTranslation);
  461.     for (FW_XYSelector vhs = FW_kHorizontal; vhs <= FW_kVertical; ++vhs)
  462.     {
  463.         PrivAdjustTranslations(ev, vhs, boundsInContent[FW_kTopLeft][vhs], boundsInContent.Length(vhs));
  464.         if (fTranslation[vhs] != oldPos[vhs])
  465.         {
  466.             FW_CAcquiredODShape tempShape = PrivCreateContentScrollShape(ev, vhs);
  467.             fFrame->GetODFrame(ev)->Invalidate(ev, tempShape, NULL);
  468.             PrivChangeFrameInternalTransform(ev, oldPos, fTranslation, vhs, FALSE);
  469.         }
  470.     }
  471. }
  472.  
  473. //----------------------------------------------------------------------------------------
  474. // FW_CScroller::ScrollPositionChanged
  475. //----------------------------------------------------------------------------------------
  476.  
  477. void FW_CScroller::ScrollPositionChanged(Environment* ev, FW_Fixed oldPos, FW_Fixed newPos, FW_XYSelector direction)
  478. {
  479. FW_UNUSED(ev);
  480. FW_UNUSED(oldPos);
  481. FW_UNUSED(newPos);
  482. FW_UNUSED(direction);
  483. }
  484.  
  485. //----------------------------------------------------------------------------------------
  486. // FW_CScroller::InitializeAutoScroll
  487. //----------------------------------------------------------------------------------------
  488.  
  489. void FW_CScroller::InitializeAutoScroll(Environment* ev)
  490. {
  491. FW_UNUSED(ev);
  492.  
  493.     fAutoScrollStage = kOutStage;
  494. }
  495.  
  496. //----------------------------------------------------------------------------------------
  497. // FW_CScroller::GetPageUnit
  498. //----------------------------------------------------------------------------------------
  499.  
  500. FW_Fixed FW_CScroller::GetPageUnit(Environment* ev, FW_XYSelector direction) const
  501. {
  502.     FW_CRect boundsInContent = GetScrollingArea(ev);
  503.     FW_Fixed pageUnit = boundsInContent.Length(direction) - fScrollUnit[direction];
  504.     if (pageUnit < fScrollUnit[direction])
  505.         pageUnit = fScrollUnit[direction];
  506.     return pageUnit;    
  507. }
  508.  
  509. //----------------------------------------------------------------------------------------
  510. // FW_CScroller::PrivLimitScrolling
  511. //----------------------------------------------------------------------------------------
  512.  
  513. void FW_CScroller::PrivLimitScrolling(FW_CPoint& scrollBy) const
  514. {
  515.     for (FW_XYSelector vhs = FW_kHorizontal; vhs <= FW_kVertical; ++vhs)
  516.     {
  517.         if (fTranslation[vhs] + scrollBy[vhs] > fMaxTranslation[vhs])
  518.             scrollBy[vhs] = fMaxTranslation[vhs] - fTranslation[vhs];
  519.         else if (fTranslation[vhs] + scrollBy[vhs] < FW_kFixed0)
  520.             scrollBy[vhs] = - fTranslation[vhs];
  521.     }
  522. }
  523.  
  524. //----------------------------------------------------------------------------------------
  525. // FW_CScroller::PrivRealignScroller
  526. //----------------------------------------------------------------------------------------
  527. // PrivRealignScroller doesn't notify anybody. Just Changes the fTranslation field
  528.  
  529. void FW_CScroller::PrivRealignScroller(Environment* ev)
  530. {    
  531.     FW_CRect boundsInContent = GetScrollingArea(ev);
  532.  
  533.     for (FW_XYSelector vhs = FW_kHorizontal; vhs <= FW_kVertical; ++vhs)
  534.         PrivAdjustTranslations(ev, 
  535.                             vhs, 
  536.                             boundsInContent[FW_kTopLeft][vhs], 
  537.                             boundsInContent.Length(vhs));
  538. }
  539.  
  540. //----------------------------------------------------------------------------------------
  541. // FW_CScroller::AutoScrollOffset
  542. //----------------------------------------------------------------------------------------
  543.  
  544. FW_CPoint FW_CScroller::AutoScrollOffset(Environment* ev, 
  545.                                         const FW_CPoint& currentPoint, 
  546.                                         unsigned long delay)
  547. {
  548.     FW_CPoint scroll(FW_kZeroPoint);
  549.     
  550.     if (fScrollUnit != FW_kZeroPoint)
  551.     {
  552.         FW_CPoint delta;
  553.         
  554.         FW_CRect content = fFrame->GetContentView(ev)->GetBoundsInContent(ev);
  555.  
  556.         FW_CRect bounds(content);
  557.         
  558.         bounds.Inset(fAutoScrollInset);
  559.         
  560.         switch (::FW_RegionCode(currentPoint, bounds))
  561.         {
  562.             case 9:
  563.                 scroll = -fScrollUnit;
  564.                 delta.x = currentPoint.x - content.left;
  565.                 delta.y = currentPoint.y - content.top;
  566.                 break;
  567.             case 1:
  568.                 scroll.y = -fScrollUnit.y;
  569.                 delta.y = currentPoint.y - content.top;
  570.                 break;
  571.             case 5:
  572.                 scroll.x = fScrollUnit.x;
  573.                 scroll.y = -fScrollUnit.y;
  574.                 delta.x = content.right - currentPoint.x;
  575.                 delta.y = currentPoint.y - content.top;
  576.                 break;
  577.             case 8:
  578.                 scroll.x = -fScrollUnit.x;
  579.                 delta.x = currentPoint.x - content.left;
  580.                 break;
  581.             case 4:
  582.                 scroll.x = fScrollUnit.x;
  583.                 delta.x = content.right - currentPoint.x;
  584.                 break;
  585.             case 10:
  586.                 scroll.x = -fScrollUnit.x;
  587.                 scroll.y = fScrollUnit.y;
  588.                 delta.x = currentPoint.x - content.left;
  589.                 delta.y = content.bottom - currentPoint.y;
  590.                 break;
  591.             case 2:
  592.                 scroll.y = fScrollUnit.y;
  593.                 delta.y = content.bottom - currentPoint.y;
  594.                 break;
  595.             case 6:
  596.                 scroll = fScrollUnit;
  597.                 delta.x = content.right - currentPoint.x;
  598.                 delta.y = content.bottom - currentPoint.y;
  599.                 break;
  600.         }
  601.         
  602.         if (scroll != FW_kZeroPoint)
  603.         {
  604.             if (delta.x < FW_kFixed0)
  605.                 delta.x = FW_kFixed0;
  606.             if (delta.y < FW_kFixed0)
  607.                 delta.y = FW_kFixed0;
  608.             
  609.             scroll.x = FW_RoundedToInt(((fAutoScrollInset - delta.x) * scroll.x) / fAutoScrollInset);
  610.             scroll.y = FW_RoundedToInt(((fAutoScrollInset - delta.y) * scroll.y) / fAutoScrollInset);
  611.             
  612.             PrivLimitScrolling(scroll);
  613.             
  614.             if (delay != 0)
  615.             {
  616.                 if (fAutoScrollStage == kOutStage)
  617.                 {
  618.                     fLastAutoScrollTick = ::FW_GetTickCount();
  619.                     fAutoScrollStage = kDelayStage;
  620.                     scroll = FW_kZeroPoint;
  621.                 }                    
  622.                 else if (fAutoScrollStage == kDelayStage)
  623.                 {
  624.                     if (::FW_GetTickCount() - fLastAutoScrollTick < delay)
  625.                         scroll = FW_kZeroPoint;
  626.                     else
  627.                         fAutoScrollStage = kScrollStage;
  628.                 }            
  629.             }                        
  630.         
  631.             // ----- Make sure that we don't scroll in an unwanted direction -----
  632.             if (fScrollUnit.x == FW_kFixed0)
  633.                 scroll.x = FW_kFixed0;
  634.             if (fScrollUnit.y == FW_kFixed0)
  635.                 scroll.y = FW_kFixed0;
  636.         }
  637.         else
  638.             fAutoScrollStage = kOutStage;
  639.     }
  640.     
  641.     return scroll;
  642. }
  643.  
  644. //----------------------------------------------------------------------------------------
  645. // FW_CScroller::ScrollBy
  646. //----------------------------------------------------------------------------------------
  647. //    a positive offset means we are scrolling down (down arrow)
  648.  
  649. void FW_CScroller::ScrollBy(Environment* ev, const FW_CPoint& offset, FW_CGraphicContext* gc)
  650. {
  651.     // ----- Validate the offset -----
  652.     FW_CPoint scroll(offset);
  653.     PrivLimitScrolling(scroll);
  654.         
  655.     PrivScrollBy(ev, scroll, gc);
  656. }
  657.  
  658. //----------------------------------------------------------------------------------------
  659. // FW_CScroller::ScrollTo
  660. //----------------------------------------------------------------------------------------
  661.  
  662. void FW_CScroller::ScrollTo(Environment* ev, const FW_CPoint& position, FW_CGraphicContext* gc)
  663. {
  664.     ScrollBy(ev, position - fTranslation, gc);
  665. }
  666.  
  667. //----------------------------------------------------------------------------------------
  668. // FW_CScroller::RevealRect
  669. //----------------------------------------------------------------------------------------
  670. //    RevealRect always shows the topleft corner of rectToReveal
  671.  
  672. void FW_CScroller::RevealRect(Environment* ev, 
  673.                              const FW_CRect& rectToReveal,
  674.                              FW_CGraphicContext* gc)
  675. {
  676.     FW_CRect boundsInContent = fFrame->GetContentView(ev)->GetBoundsInContent(ev);
  677.     FW_CPoint extent = fFrame->GetContentView(ev)->GetExtent(ev);
  678.  
  679.     FW_CPoint scrollTo = boundsInContent[FW_kTopLeft];
  680.     if (rectToReveal.left < boundsInContent.left)
  681.     {
  682.         scrollTo.x = rectToReveal.left;
  683.     }
  684.     else if (rectToReveal.right > boundsInContent.right)
  685.     {
  686.         scrollTo.x = rectToReveal.right - (boundsInContent.right - boundsInContent.left);
  687.         if (scrollTo.x > rectToReveal.left)
  688.             scrollTo.x = rectToReveal.left;
  689.     }
  690.  
  691.     if (rectToReveal.top < boundsInContent.top)
  692.     {
  693.         scrollTo.y = rectToReveal.top;
  694.     }
  695.     else if (rectToReveal.bottom > boundsInContent.bottom)
  696.     {
  697.         scrollTo.y = rectToReveal.bottom - (boundsInContent.bottom - boundsInContent.top);
  698.         if (scrollTo.y > rectToReveal.top)
  699.             scrollTo.y = rectToReveal.top;
  700.     }
  701.  
  702.     if (scrollTo != boundsInContent[FW_kTopLeft])
  703.         ScrollTo(ev, scrollTo, gc);
  704. }
  705.  
  706. //----------------------------------------------------------------------------------------
  707. // FW_CScroller::PrivScrollBy
  708. //----------------------------------------------------------------------------------------
  709. //    PrivScrollBy doesn't make any validation on the offset
  710.  
  711. void FW_CScroller::PrivScrollBy(Environment* ev, const FW_CPoint& offset, FW_CGraphicContext* gc)
  712. {
  713.     if (offset != FW_kZeroPoint)
  714.     {
  715.         FW_CPoint odlPos = fTranslation;
  716.         
  717.         // ----- I have to do that because I can't call PrivChangeFrameInternalTransform with both
  718.         // ----- x and y changing.
  719.         for (FW_XYSelector vhs = FW_kHorizontal; vhs <= FW_kVertical; ++vhs)
  720.         {
  721.             fTranslation[vhs] += offset[vhs];
  722.             PrivChangeFrameInternalTransform(ev, odlPos, fTranslation, vhs, TRUE);
  723.         }
  724.         
  725.         if (gc)
  726.             gc->Reset();            
  727.     }
  728. }
  729.  
  730. //----------------------------------------------------------------------------------------
  731. // FW_CScroller::AutoScroll
  732. //----------------------------------------------------------------------------------------
  733. //    currentPoint is in content coordinates
  734.  
  735. void FW_CScroller::AutoScroll(Environment* ev, 
  736.                                 const FW_CPoint& currentPoint, 
  737.                                 FW_CGraphicContext* gc,
  738.                                 unsigned long delay)
  739. {    
  740.     PrivScrollBy(ev, AutoScrollOffset(ev, currentPoint, delay), gc);
  741. }
  742.  
  743. //----------------------------------------------------------------------------------------
  744. //    FW_CScroller::HandlePageNavigationKeys
  745. //----------------------------------------------------------------------------------------
  746.  
  747. FW_Handled FW_CScroller::HandlePageNavigationKeys(Environment* ev, const FW_CVirtualKeyEvent& theVirtualKeyEvent)
  748. {    
  749.     FW_Fixed pageScroll = FW_RoundedToInt(GetPageUnit(ev, FW_kVertical));
  750.  
  751.     FW_Handled result = FW_kHandled;
  752.     switch (theVirtualKeyEvent.GetKeyCode(ev))
  753.     {
  754.         case FW_kVKPageUp:
  755.             ScrollBy(ev, FW_CPoint(FW_kFixed0, -pageScroll));
  756.             break;
  757.         case FW_kVKPageDown:
  758.             ScrollBy(ev, FW_CPoint(FW_kFixed0, pageScroll));
  759.             break;    
  760.         case FW_kVKEnd:
  761.             ScrollTo(ev, FW_CPoint(FW_kFixed0, fMaxTranslation[FW_kVertical]), NULL);
  762.             break;
  763.         case FW_kVKHome:
  764.             ScrollTo(ev, FW_kZeroPoint, NULL);
  765.             break;
  766.         default:
  767.             result = FW_kNotHandled;
  768.     }
  769.     
  770.     return result;
  771. }
  772.  
  773. //----------------------------------------------------------------------------------------
  774. // FW_CScroller::PrivCreateContentScrollShape
  775. //----------------------------------------------------------------------------------------
  776. // This returns the shape (in Frame coord.) composed of the ContentView + all the views
  777. // scrolling in X or Y with the content.  
  778.  
  779. ODShape* FW_CScroller::PrivCreateContentScrollShape(Environment* ev, FW_XYSelector direction) const
  780. {
  781.     FW_CSuperView* contentView = fFrame->GetContentView(ev);
  782.     FW_ASSERT(contentView);
  783.     
  784.     // ----- Get the contentView first
  785.     ODShape* scrollShape = ::FW_NewODShape(ev, FW_CRect(FW_kZeroPoint, contentView->GetSize(ev)));
  786.     contentView->ViewToFrame(ev, scrollShape);
  787.  
  788.     // ----- Acquire the content scroll shape
  789.     fFrame->PrivAcquireContentScrollShape(ev, direction, scrollShape);
  790.     
  791.     return scrollShape;
  792. }
  793.  
  794. //----------------------------------------------------------------------------------------
  795. //    FW_CScroller::Flatten
  796. //----------------------------------------------------------------------------------------
  797.  
  798. void FW_CScroller::Flatten(Environment* ev, FW_CWritableStream& stream) const
  799. {
  800.     FW_CFrame* frame = fFrame;
  801. #ifdef FW_DEBUG
  802.     FW_OObjectRegistry*    registry = stream.GetRegistry();
  803.     frame = (FW_CFrame*) registry->LookupByID(ev, FW_kPreregisteredFrameObject);
  804.     FW_ASSERT(frame == fFrame);
  805. #else
  806. FW_UNUSED(ev);
  807. #endif
  808.  
  809.     FW_WRITE_DYNAMIC_OBJECT(stream, frame, FW_CFrame);
  810.     stream << fAutoScrollInset;
  811.     stream << fScrollUnit;
  812.     stream << fHandlePageNavigationKeys;
  813. }
  814.  
  815. //----------------------------------------------------------------------------------------
  816. //    FW_CScroller::InitializeFromStream
  817. //----------------------------------------------------------------------------------------
  818.  
  819. void FW_CScroller::InitializeFromStream(Environment* ev, FW_CReadableStream& stream)
  820. {
  821. #ifdef FW_DEBUG
  822.     FW_OObjectRegistry*    registry = stream.GetRegistry();
  823.     FW_CFrame* frame = (FW_CFrame*) registry->LookupByID(ev, FW_kPreregisteredFrameObject);
  824.     FW_ASSERT(frame != 0);
  825. #else
  826. FW_UNUSED(ev);
  827. #endif
  828.  
  829.     FW_READ_DYNAMIC_OBJECT(stream, &fFrame, FW_CFrame);
  830.     FW_ASSERT(frame == fFrame);
  831.     
  832.     stream >> fAutoScrollInset;
  833.     stream >> fScrollUnit;
  834.     stream >> fHandlePageNavigationKeys;
  835. }
  836.  
  837. //========================================================================================
  838. // CLASS FW_CScrollBarScroller
  839. //========================================================================================
  840.  
  841. FW_DEFINE_AUTO(FW_CScrollBarScroller)
  842. FW_DEFINE_CLASS_M1(FW_CScrollBarScroller, FW_CScroller)
  843.  
  844. // This class is archivable, but we provide the archiving implementation in a separate
  845. // translation unit in order to enable deadstripping of the archiving-related code
  846. // in parts that do not use archiving with this class.
  847.  
  848. //----------------------------------------------------------------------------------------
  849. // FW_CScrollBarScroller::FW_CScrollBarScroller
  850. //----------------------------------------------------------------------------------------
  851.  
  852. FW_CScrollBarScroller::FW_CScrollBarScroller(Environment* ev, 
  853.                                              FW_CFrame* frame,
  854.                                              FW_Boolean liveScrolling,
  855.                                              FW_CScrollBar* horzSB, 
  856.                                              FW_CScrollBar* vertSB) :
  857.     FW_CScroller(ev, frame),
  858.     fLiveScrolling(liveScrolling)
  859. {
  860.     fScrollbars[FW_kHorizontal] = horzSB;
  861.     fScrollbars[FW_kVertical] = vertSB;
  862.     
  863.     PrivAttachScrollBars(ev);
  864.     
  865.     FW_END_CONSTRUCTOR
  866. }
  867.  
  868. //----------------------------------------------------------------------------------------
  869. // FW_CScrollBarScroller::FW_CScrollBarScroller
  870. //----------------------------------------------------------------------------------------
  871.  
  872. FW_CScrollBarScroller::FW_CScrollBarScroller(Environment* ev) :
  873.     FW_CScroller(ev),
  874.     fLiveScrolling(FALSE)
  875. {
  876.     FW_END_CONSTRUCTOR
  877. }
  878.  
  879. //----------------------------------------------------------------------------------------
  880. // FW_CScrollBarScroller::~FW_CScrollBarScroller
  881. //----------------------------------------------------------------------------------------
  882.  
  883. FW_CScrollBarScroller::~FW_CScrollBarScroller()
  884. {
  885.     FW_START_DESTRUCTOR
  886.     
  887.     // Don't delete the scroll bars, we don't own them! The containing view
  888.     // or frame owns them.
  889.     
  890.     FW_SOMEnvironment ev;
  891.     
  892.     for (FW_XYSelector vhs = FW_kHorizontal; vhs <= FW_kVertical; ++vhs)
  893.     {
  894.         FW_CScrollBar* scrollbar = fScrollbars[vhs];
  895.         if (scrollbar)
  896.         {
  897.             UnregisterScrollNotifier(ev, scrollbar);
  898.             scrollbar->PrivAttachToScroller(ev, NULL);    
  899.         }
  900.     }
  901. }
  902.  
  903. //----------------------------------------------------------------------------------------
  904. // FW_CScrollBarScroller::ScrollPositionChanged
  905. //----------------------------------------------------------------------------------------
  906.  
  907. void FW_CScrollBarScroller::ScrollPositionChanged(Environment* ev, 
  908.                                                     FW_Fixed oldPos, 
  909.                                                     FW_Fixed newPos, 
  910.                                                     FW_XYSelector direction)
  911. {
  912.     FW_CScroller::ScrollPositionChanged(ev, oldPos, oldPos, direction);
  913.     
  914.     FW_CScrollBar* sb = fScrollbars[direction];
  915.     if (sb != NULL && sb->GetScrollPos(ev) != newPos)
  916.         sb->SetScrollPos(ev, newPos);
  917. }
  918.  
  919. //----------------------------------------------------------------------------------------
  920. // FW_CScrollBarScroller::PrivAdjustTranslations
  921. //----------------------------------------------------------------------------------------
  922.  
  923. void FW_CScrollBarScroller::PrivAdjustTranslations(Environment* ev, 
  924.                                                     FW_XYSelector direction, 
  925.                                                     FW_Fixed translation, 
  926.                                                     FW_Fixed scrollingArea)
  927. {    
  928.     FW_Fixed oldMax = fMaxTranslation[direction];
  929.     
  930.     FW_Boolean wasEnabled = fMaxTranslation[direction] > FW_kFixed0;
  931.  
  932.     FW_Fixed oldPos = fTranslation[direction];
  933.     FW_CScroller::PrivAdjustTranslations(ev, direction, translation, scrollingArea);
  934.     
  935.     FW_Boolean isEnabled = fMaxTranslation[direction] > FW_kFixed0;
  936.  
  937.     FW_CScrollBar* sb = fScrollbars[direction];
  938.     if (sb)
  939.     {
  940.         // ----- Update scrollbar Major and Minor scroll units
  941.         sb->SetMinorScrollUnits(ev, FW_RoundedToInt(GetScrollUnit(ev, direction)));
  942.         sb->SetMajorScrollUnits(ev, FW_RoundedToInt(GetPageUnit(ev, direction)));
  943.  
  944.         // ----- Set scrollbar maximum -----
  945.         sb->SetScrollMax(ev, fMaxTranslation[direction]);
  946.  
  947.         if (fTranslation[direction] != oldPos || fMaxTranslation[direction] != oldMax)
  948.             sb->SetScrollPos(ev, fMaxTranslation[direction], fTranslation[direction]);    
  949.         
  950.         // [HLX] we should be able to remove that when Laurent fixes the invalidation problem
  951.         // in SetScrollPos                
  952.         if (wasEnabled != isEnabled)
  953.             sb->Invalidate(ev);
  954.     }
  955. }
  956.  
  957. //----------------------------------------------------------------------------------------
  958. //    FW_CScrollBarScroller::RemoveScrollBar
  959. //----------------------------------------------------------------------------------------
  960. // This doesn't delete the scrollbar view itself
  961.  
  962. void FW_CScrollBarScroller::RemoveScrollBar(Environment* ev, FW_XYSelector direction) 
  963. {
  964. FW_UNUSED(ev);
  965.     FW_CScrollBar* sb = fScrollbars[direction];
  966.     if (sb == NULL)
  967.         return;
  968.     
  969.     // Remove the connection first    
  970.     RemoveInterest(FW_CInterest(sb, FW_kScrollMsg));
  971.     
  972.     fScrollbars[direction] = NULL;
  973. }
  974.  
  975. //----------------------------------------------------------------------------------------
  976. //    FW_CScrollBarScroller::Flatten
  977. //----------------------------------------------------------------------------------------
  978.  
  979. void FW_CScrollBarScroller::Flatten(Environment* ev, FW_CWritableStream& stream) const
  980. {
  981.     FW_CScroller::Flatten(ev, stream);
  982.     
  983.     stream << fLiveScrolling;
  984.     
  985.     ODID horizScrollBarID = kODNULLID;
  986.     ODID vertScrollBarID = kODNULLID;
  987.     
  988.     if (fScrollbars[FW_kHorizontal])
  989.         horizScrollBarID = fScrollbars[FW_kHorizontal]->GetViewID(ev);
  990.     if (fScrollbars[FW_kVertical])
  991.         vertScrollBarID = fScrollbars[FW_kVertical]->GetViewID(ev);
  992.  
  993.     stream << horizScrollBarID << vertScrollBarID;
  994. }
  995.  
  996. //----------------------------------------------------------------------------------------
  997. //    FW_CScrollBarScroller::InitializeFromStream
  998. //----------------------------------------------------------------------------------------
  999.  
  1000. void FW_CScrollBarScroller::InitializeFromStream(Environment* ev, FW_CReadableStream& stream)
  1001. {
  1002.     FW_CScroller::InitializeFromStream(ev, stream);
  1003.  
  1004.     stream >> fLiveScrolling;
  1005.     
  1006.     ODID horizScrollBarID;
  1007.     ODID vertScrollBarID;
  1008.     stream >> horizScrollBarID >> vertScrollBarID;
  1009.  
  1010.     FW_CView* hScrollBarView = NULL;
  1011.     if (horizScrollBarID != kODNULLID)
  1012.         hScrollBarView = fFrame->FindViewByID(ev, horizScrollBarID);
  1013.  
  1014.     FW_CView* vScrollBarView = NULL;
  1015.     if (vertScrollBarID != kODNULLID)
  1016.         vScrollBarView = fFrame->FindViewByID(ev, vertScrollBarID);
  1017.  
  1018.     fScrollbars[FW_kHorizontal] = FW_DYNAMIC_CAST(FW_CScrollBar, hScrollBarView);
  1019.     fScrollbars[FW_kVertical] = FW_DYNAMIC_CAST(FW_CScrollBar, vScrollBarView);
  1020.     
  1021.     PrivAttachScrollBars(ev);
  1022. }
  1023.  
  1024. #ifdef FW_DEBUG
  1025. //----------------------------------------------------------------------------------------
  1026. //    FW_CScrollBarScroller::PrivCheckFrame
  1027. //----------------------------------------------------------------------------------------
  1028.  
  1029. void FW_CScrollBarScroller::PrivCheckFrame(Environment* ev) const
  1030. {
  1031.     // We cannot authorize frames to use a scroller with scrollbars in case they don't have 
  1032.     // a separate content view, because the scrollbars will end up moving with the rest of 
  1033.     // frame's content!  A frame which is its own content view  can only use a basic
  1034.     // FW_CScroller instance, which can be scrolled with a hand-scrolling or auto-scrolling
  1035.     // mechanism.
  1036.  
  1037.     if (fFrame->IsContentView(ev))
  1038.     {
  1039.         FW_DEBUG_MESSAGE("Cannot use a ScrollBarScroller here, create a separate content view");
  1040.     }
  1041.  
  1042. }
  1043. #endif
  1044.  
  1045. //----------------------------------------------------------------------------------------
  1046. //    FW_CScrollBarScroller::PrivAttachScrollBars
  1047. //----------------------------------------------------------------------------------------
  1048.  
  1049. void FW_CScrollBarScroller::PrivAttachScrollBars(Environment* ev)
  1050. {
  1051.     for (FW_XYSelector vhs = FW_kHorizontal; vhs <= FW_kVertical; ++vhs)
  1052.     {
  1053.         FW_CScrollBar* scrollbar = fScrollbars[vhs];
  1054.         if (scrollbar)
  1055.         {
  1056.             RegisterScrollNotifier(ev, scrollbar);
  1057.             scrollbar->PrivAttachToScroller(ev, this);    
  1058.         }
  1059.     }
  1060. }
  1061.